#ifndef _DRIVER_ADC_H
#define _DRIVER_ADC_H
#include <stdint.h>
#include <stdbool.h>
#include "plf.h"

enum adc_channel_t{
    ADC_CHANNEL_PD0,
    ADC_CHANNEL_PD1,
    ADC_CHANNEL_PD2,
    ADC_CHANNEL_PD3,
    ADC_CHANNEL_PD4,
    ADC_CHANNEL_PD5,
    ADC_CHANNEL_PD6,
    ADC_CHANNEL_PD7,
};

enum adc_sample_sig_sel{
    SEL_IO=3,
    SEL_VBE=6,
    SEL_VBAT=7,   
};

struct adc_ctrl_reg_t{
    uint32_t adc_clk_en:1;
    uint32_t fifo_en:1;
    uint32_t adc_mode:1;    //0---loop,1---fixed channel
    uint32_t data_valid:1;
    uint32_t adc_sel:3;     //in fixed mode channel select
    uint32_t adc_en:1;      //adc block enable    
    uint32_t ch_en_mask:8;
    uint32_t rxfltr:6;
    uint32_t push_fifo_flag:1;//channel NO pushed to fifo
    uint32_t dmacr:1;       //dma handshake enable
    uint32_t dmardlr:6;     //dma trigger threshold
    uint32_t adc_trig_sw:1;
    uint32_t fifo_clr:1;
};

struct adc_data_reg_t{
    uint32_t adc_data:10;
    uint32_t ch_num:3;        //only valid @fifo mode
    uint32_t pwm_trig_sts:1;  //only valid @fifo mode
    uint32_t resv:18;
};

struct adc_int_raw_reg_t{
    uint32_t ff_int_raw:1;
    uint32_t fe_int_raw:1;
    uint32_t faf_int_raw:1;
    uint32_t fov_int_raw:1;
    uint32_t fud_int_raw:1;
    uint32_t resv:27;
};

struct adc_int_ctrl_sts_reg_t{
    uint32_t ff_int_en:1;
    uint32_t fe_int_en:1;
    uint32_t faf_int_en:1;
    uint32_t fov_int_en:1;
    uint32_t fud_int_en:1;
    uint32_t err_int_en:1;
    uint32_t sw_int_en:1;
    uint32_t pwm0_pos_int_en:1;
    uint32_t pwm1_pos_int_en:1;
    uint32_t pwm2_pos_int_en:1;
    uint32_t pwm3_pos_int_en:1;
    uint32_t pwm0_neg_int_en:1;
    uint32_t pwm1_neg_int_en:1;
    uint32_t pwm2_neg_int_en:1;
    uint32_t pwm3_neg_int_en:1;
    uint32_t resv0:1;
    uint32_t ff_int_sts:1;
    uint32_t fe_int_sts:1;
    uint32_t faf_int_sts:1;
    uint32_t fov_int_sts:1;
    uint32_t fud_int_sts:1;
    uint32_t err_int_sts:1;
    uint32_t sw_trig_done_st:1;
    uint32_t pwm0_pos_done_st:1;
    uint32_t pwm1_pos_done_st:1;
    uint32_t pwm2_pos_done_st:1;
    uint32_t pwm3_pos_done_st:1;
    uint32_t pwm0_neg_done_st:1;
    uint32_t pwm1_neg_done_st:1;
    uint32_t pwm2_neg_done_st:1;
    uint32_t pwm3_neg_done_st:1;
    uint32_t resv1:1;
};

struct adc_int_clc_reg_t {
    uint32_t ff_int_clr:1;
    uint32_t fe_int_clr:1;
    uint32_t faf_int_clr:1;
    uint32_t fov_int_clr:1;
    uint32_t fud_int_clr:1;
    uint32_t err_int_clr:1;
    uint32_t sw_done_clr:1;
    uint32_t pwm0_pos_clr:1;
    uint32_t pwm1_pos_clr:1;
    uint32_t pwm2_pos_clr:1;
    uint32_t pwm3_pos_clr:1;
    uint32_t pwm0_neg_clr:1;
    uint32_t pwm1_neg_clr:1;
    uint32_t pwm2_neg_clr:1;
    uint32_t pwm3_neg_clr:1;
    uint32_t rsv:17;
};

struct adc_ana_pdclk_reg_t {
    uint32_t adc_pd:1;
    uint32_t adc_rstn:1;
    uint32_t adc_ison:1;
    uint32_t clk_edge_ctl:1;
    uint32_t saclk_ctl:1;
    uint32_t sample_sig_sel:3;
    uint32_t clk_div:8;
    uint32_t capt_len:16;
};

struct adc_ana_cfg_reg_t {
    uint32_t input_swap:1;
    uint32_t buf_en:1;
    uint32_t buf_in_sel:1;
    uint32_t refh_mode:1;
    uint32_t vbat_div_en:1;
    uint32_t refh_ext_en:1;
    uint32_t cap_trim:3;
    uint32_t ref1p2_buf_en:1;
    uint32_t reflp2_buf_rl:4;
    uint32_t in_div_en:1;
    uint32_t in_div_power_sel:1;
    uint32_t in_div_rat:2;
    uint32_t in_div_res:2;
    uint32_t in_div_cap:4;
    uint32_t resv:8;
};

struct adc_mode_ctrl_reg_t{
    uint32_t poll_mode:1;   //0-- infinite loop 1-- single trigger
    uint32_t tout_mask:1;   //0-- disable analog convert fsm error check 1-- enable analog convert error check
    uint32_t conv_time:5;   //analog convert time-out cnt set
    uint32_t adc_en_mask:9;   //adc convert enable
    uint32_t sample_point:8;
    uint32_t resv:8;
};

enum adc_en_mask_t{
    CPU_SW_TRIG,
    PWM0_POS_TRIG,
    PWM1_POS_TIRG,
    PWM2_POS_TRIG,
    PWM3_POS_TRIG,
    PWM0_NEG_TRIG,
    PWM1_NEG_TRIG,
    PWM2_NEG_TRIG,
    PWM3_NEG_TRIG
};

struct saradc_reg_t{
    struct adc_ctrl_reg_t ctrl;    
    volatile uint32_t data[8];
    struct adc_data_reg_t data_reg;         //0x24
    struct adc_int_raw_reg_t int_raw;       //0x28
    struct adc_int_ctrl_sts_reg_t int_cs;   //0x2C
    struct adc_int_clc_reg_t int_clc;       //0x30
    struct adc_ana_pdclk_reg_t ana_pwrclk;  //0x34
    struct adc_ana_cfg_reg_t adc_cfg;
    struct adc_mode_ctrl_reg_t mode_ctrl;
};

/*********************************************************************
 * @fn      saradc_init
 *
 * @brief   initiate ADC with parameters.
 *          The adc module works in low sample rate mode (1K) if more than
 *          one channels are enabled, otherwise higher sample rate (1M) will
 *          be used default.
 *
 * @param   channel     - adc channel, @ref adc_channel_t.
 *          sample_sel  -select adc input channel, @ref adc_sample_sig_sel.
 *          fifo_en     -1:enable fifo mode,0:disable fifo mode.
 *          ref_sel     -0:IO as reference,1:internal 1.2v buffer.
 *          fix_ch_en   -0:channel loop mode,1= channel fixed mode.
 *
 * @return  None.
 */
void saradc_init(enum adc_channel_t channel,enum adc_sample_sig_sel sample_sel, uint8_t fifo_en,uint8_t ref_sel,bool fix_ch_en);

/*********************************************************************
 * @fn      saradc_enable
 *
 * @brief   after adc is initiated, call this function to start AD-convert.
 *          user should call saradc_get_data to fetch value manually.        
 * @param   none
 *       
 * @return  none
 */
void saradc_enable(void);

/*********************************************************************
 * @fn      saradc_disable
 *
 * @brief   disable ongoing AD-convert.
 *
 * @param   None.
 *       
 * @return  None.
 */
void saradc_disable(void);

/*********************************************************************
 * @fn      saradc_get_data
 *
 * @brief   size	-how many channels to be read,1~8 @ref adc_channel_t.
 *		    buf    	-store the result of AD-convert 
 *			chnl	-output channel,refer to @ref adc_channel_t. 
 *    
 * @param   None.
 *       
 * @return  None.
 */
void saradc_get_data(uint16_t size,uint16_t *buf,uint8_t chnl);

void demo_adc();

#endif